// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
 *******************************************************************************
 * Copyright (C) 2003-2014, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 */
package com.ibm.icu.text;

import java.text.ParseException;

/**
 * Exception that signals an error has occurred while parsing the input to StringPrep or IDNA.
 *
 * @author Ram Viswanadha
 * @stable ICU 2.8
 */
public class StringPrepParseException extends ParseException {
    // Generated by serialver from JDK 1.4.1_01
    static final long serialVersionUID = 7160264827701651255L;

    /**
     * @stable ICU 2.8
     */
    public static final int INVALID_CHAR_FOUND = 0;

    /**
     * @stable ICU 2.8
     */
    public static final int ILLEGAL_CHAR_FOUND = 1;

    /**
     * @stable ICU 2.8
     */
    public static final int PROHIBITED_ERROR = 2;

    /**
     * @stable ICU 2.8
     */
    public static final int UNASSIGNED_ERROR = 3;

    /**
     * @stable ICU 2.8
     */
    public static final int CHECK_BIDI_ERROR = 4;

    /**
     * @stable ICU 2.8
     */
    public static final int STD3_ASCII_RULES_ERROR = 5;

    /**
     * @stable ICU 2.8
     */
    public static final int ACE_PREFIX_ERROR = 6;

    /**
     * @stable ICU 2.8
     */
    public static final int VERIFICATION_ERROR = 7;

    /**
     * @stable ICU 2.8
     */
    public static final int LABEL_TOO_LONG_ERROR = 8;

    /**
     * @stable ICU 2.8
     */
    public static final int BUFFER_OVERFLOW_ERROR = 9;

    /**
     * @stable ICU 2.8
     */
    public static final int ZERO_LENGTH_LABEL = 10;

    /**
     * @stable ICU 3.8
     */
    public static final int DOMAIN_NAME_TOO_LONG_ERROR = 11;

    /**
     * Construct a ParseException object with the given message and error code
     *
     * @param message A string describing the type of error that occurred
     * @param error The error that has occurred
     * @stable ICU 2.8
     */
    public StringPrepParseException(String message, int error) {
        super(message, -1);
        this.error = error;
        this.line = 0;
    }

    /**
     * Construct a ParseException object with the given message and error code
     *
     * @param message A string describing the type of error that occurred
     * @param error The error that has occurred
     * @param rules The input rules string
     * @param pos The position of error in the rules string
     * @stable ICU 2.8
     */
    public StringPrepParseException(String message, int error, String rules, int pos) {
        super(message, -1);
        this.error = error;
        setContext(rules, pos);
        this.line = 0;
    }

    /**
     * Construct a ParseException object with the given message and error code
     *
     * @param message A string describing the type of error that occurred
     * @param error The error that has occurred
     * @param rules The input rules string
     * @param pos The position of error in the rules string
     * @param lineNumber The line number at which the error has occurred. If the parse engine is not
     *     using this field, it should set it to zero. Otherwise it should be a positive integer.
     *     The default value of this field is -1. It will be set to 0 if the code populating this
     *     struct is not using line numbers.
     * @stable ICU 2.8
     */
    public StringPrepParseException(
            String message, int error, String rules, int pos, int lineNumber) {
        super(message, -1);
        this.error = error;
        setContext(rules, pos);
        this.line = lineNumber;
    }

    /**
     * Compare this ParseException to another and evaluate if they are equal. The comparison works
     * only on the type of error and does not compare the rules strings, if any, for equality.
     *
     * @param other The exception that this object should be compared to
     * @return true if the objects are equal, false if unequal
     * @stable ICU 2.8
     */
    @Override
    public boolean equals(Object other) {
        if (!(other instanceof StringPrepParseException)) {
            return false;
        }
        return ((StringPrepParseException) other).error == this.error;
    }

    /**
     * Mock implementation of hashCode(). This implementation always returns a constant value. When
     * Java assertion is enabled, this method triggers an assertion failure.
     *
     * @return a hash code value for this object.
     * @stable ICU 2.8
     */
    @Override
    public int hashCode() {
        assert false : "hashCode not designed";
        return 42;
    }

    /**
     * Returns the position of error in the rules string
     *
     * @return String
     * @stable ICU 2.8
     */
    @Override
    public String toString() {
        StringBuilder buf = new StringBuilder();
        buf.append(super.getMessage());
        buf.append(". line:  ");
        buf.append(line);
        buf.append(". preContext:  ");
        buf.append(preContext);
        buf.append(". postContext: ");
        buf.append(postContext);
        buf.append("\n");
        return buf.toString();
    }

    private int error;

    /**
     * The line on which the error occurred. If the parse engine is not using this field, it should
     * set it to zero. Otherwise it should be a positive integer. The default value of this field is
     * -1. It will be set to 0 if the code populating this struct is not using line numbers.
     */
    private int line;

    /**
     * Textual context before the error. Null-terminated. May be the empty string if not implemented
     * by parser.
     */
    private StringBuffer preContext = new StringBuffer();

    /**
     * Textual context after the error. Null-terminated. May be the empty string if not implemented
     * by parser.
     */
    private StringBuffer postContext = new StringBuffer();

    private static final int PARSE_CONTEXT_LEN = 16;

    private void setPreContext(String str, int pos) {
        setPreContext(str.toCharArray(), pos);
    }

    private void setPreContext(char[] str, int pos) {
        int start = (pos <= PARSE_CONTEXT_LEN) ? 0 : (pos - (PARSE_CONTEXT_LEN - 1));
        int len = (start <= PARSE_CONTEXT_LEN) ? start : PARSE_CONTEXT_LEN;
        preContext.append(str, start, len);
    }

    private void setPostContext(String str, int pos) {
        setPostContext(str.toCharArray(), pos);
    }

    private void setPostContext(char[] str, int pos) {
        int start = pos;
        int len = str.length - start;
        postContext.append(str, start, len);
    }

    private void setContext(String str, int pos) {
        setPreContext(str, pos);
        setPostContext(str, pos);
    }

    /**
     * Returns the error code of this exception. This method is only used for testing to verify the
     * error.
     *
     * @return The error code
     * @stable ICU 3.8
     */
    public int getError() {
        return error;
    }
}
